﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using anks.Components;
using pygs.Messaging.Buffer;
using pygs.Messaging.Transport;

namespace pygs.Messaging
{
    class FwMessaging : CustomMessaging
    {
        private CustomBuffer _buffer;
        protected CustomBuffer buffer { get { return _buffer; } }
        private CustomTransport _transport;
        protected CustomTransport transport { get { return _transport; } }
        protected int granularity { get; set; }
        protected bool isThreading { get; set; }

        protected override void InitilizeComponent()
        {
            base.InitilizeComponent();
            _buffer = (CustomBuffer)context.GetImplementation("messaging.buffer");
            _transport = (CustomTransport)context.GetImplementation("messaging.transport");
            _transportThread = new Thread(DoTransport);
        }

        protected override void DoStartUp()
        {
            base.DoStartUp();
            if (isThreading)
                transportThread.Start();
        }

        protected override void DoShutDown()
        {
            transportThread.Abort();
            CheckBuffer(true);
            base.DoShutDown();
        }

        public FwMessaging()
            : base()
        {
        }

        public FwMessaging(int granularity)
            : this(granularity, true)
        {
            this.granularity = granularity;
        }

        public FwMessaging(int granularity, bool isThreading)
            : base()
        {
            this.granularity = granularity;
            this.isThreading = isThreading;
        }

        public override void AssignParams(ComponentParams componentParams)
        {
            this.granularity = componentParams.ParamAsInt("granularity", 1);
            this.isThreading = componentParams.ParamAsBool("isThreading", true);
        }

        private Thread _transportThread;
        protected Thread transportThread { get { return _transportThread; } }

        private void DoTransport()
        {
            while (true)
            {
                Thread.Sleep(1000);
                CheckBuffer();
            }
        }

        private void CheckBuffer()
        {
            CheckBuffer(false);
        }

        private void CheckBuffer(bool force)
        {
            if (buffer.count >= granularity || force)
            {
                // TODO: Сделать группировку одинаковых сообщений в одно.
                List<Message> list = buffer.GetTop(granularity);
                CustomTransport.SendingResult result;
                if (!SendToTransport(list, out result))
                {
                    buffer.AddToTop(result.failed);
                    context.Log().info.Log("messaging send failed");
                }
            }
        }

        private bool SendToTransport(Message message, out CustomTransport.SendingResult result)
        {
            List<Message> list = new List<Message>();
            list.Add(message);
            return SendToTransport(list, out result);
        }

        private bool SendToTransport(List<Message> list, out CustomTransport.SendingResult result)
        {
            context.Log().info.Log("messaging send to transport. count = " + Convert.ToString(list.Count));
            return transport.Send(list, out result);
        }

        public override void Send(Message message)
        {
            context.Log().info.Log("messaging send: " + message.ToString());
            buffer.Add(message);
            if (!isThreading)
                CheckBuffer();
        }
    }
}
